﻿using System;
using System.Drawing;
using System.Runtime.InteropServices;
 
using Mogre;

namespace ProjetSMA.View.Mogre
{
    public sealed class MovableText : IDisposable
{
    private Billboard billboard;
    private BillboardSet billboardSet;
    private MaterialPtr material;
    private SceneManager sceneMgr;
    private Size size;
    private TexturePtr texture;
 
    public MovableText(string name, SceneManager sceneMgr, SceneNode node, Size size)
    {
        this.texture = TextureManager.Singleton.CreateManual(
            name + "Texture",
            ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
            TextureType.TEX_TYPE_2D,
            (uint)size.Width,
            (uint)size.Height,
            0,
            PixelFormat.PF_A8R8G8B8);
 
        this.material = MaterialManager.Singleton.Create(name + "Material", ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME);
        this.material.GetTechnique(0).GetPass(0).CreateTextureUnitState(this.texture.Name);
        this.material.SetSceneBlending(SceneBlendType.SBT_TRANSPARENT_ALPHA);
        this.material.SetDepthCheckEnabled(false);
 
        this.billboardSet = sceneMgr.CreateBillboardSet();
        this.billboardSet.SetMaterialName(this.material.Name);
        this.billboardSet.RenderQueueGroup = (byte)RenderQueueGroupID.RENDER_QUEUE_OVERLAY;
 
        this.billboard = this.billboardSet.CreateBillboard(Vector3.ZERO);
        this.billboard.SetDimensions(size.Width, size.Height);
        this.billboard.Colour = ColourValue.ZERO;
 
        node.AttachObject(this.billboardSet);
        this.sceneMgr = sceneMgr;
        this.size = size;
    }
 
    public Vector3 Offset
    {
        get
        {
            return this.billboard.Position;
        }
 
        set
        {
            this.billboard.Position = value;
        }
    }
 
    public bool Visible
    {
        get
        {
            return this.billboardSet.Visible;
        }
 
        set
        {
            this.billboardSet.Visible = value;
        }
    }
 
    public void Dispose()
    {
        this.billboardSet.DetachFromParent();
        this.sceneMgr.DestroyBillboardSet(this.billboardSet);
        this.billboardSet.Dispose();
        this.billboardSet = null;
        this.sceneMgr = null;
 
        this.material.Unload();
        MaterialManager.Singleton.Remove(this.material.Handle);
        this.material.Dispose();
        this.material = null;
 
        this.texture.Unload();
        TextureManager.Singleton.Remove(this.texture.Handle);
        this.texture.Dispose();
        this.texture = null;
 
        GC.SuppressFinalize(this);
    }
 
    public void SetText(string text, System.Drawing.Font font, Color colour)
    {
        using (Bitmap bitmap = new Bitmap(this.size.Width, this.size.Height))
        {
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                using (SolidBrush brush = new SolidBrush(colour))
                {
                    g.Clear(Color.Transparent);
                    g.DrawString(text, font, brush, PointF.Empty);
                    ConvertImageToTexture(bitmap, this.texture.Name, this.size);
                }
            }
        }
    }
 
    private static unsafe void ConvertImageToTexture(Bitmap image, string textureName, Size size)
    {
        int width = size.Width;
        int height = size.Height;
        using (ResourcePtr rpt = TextureManager.Singleton.GetByName(textureName))
        {
            using (TexturePtr texture = rpt)
            {
                HardwarePixelBufferSharedPtr texBuffer = texture.GetBuffer();
                texBuffer.Lock(HardwareBuffer.LockOptions.HBL_DISCARD);
                PixelBox pb = texBuffer.CurrentLock;
 
                System.Drawing.Imaging.BitmapData data = image.LockBits(new System.Drawing.Rectangle(0, 0, width, height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                CopyMemory(pb.data, data.Scan0, (uint)(width * height * 4));
                image.UnlockBits(data);
 
                texBuffer.Unlock();
                texBuffer.Dispose();
            }
        }
    }
 
    [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
    private static extern void CopyMemory(IntPtr Destination, IntPtr Source, uint Length);
}
 
}

